package cn.cdeden.system.dubbo;

import cn.cdeden.common.core.enums.UserType;
import cn.cdeden.common.core.utils.page.TableDataInfo;
import cn.cdeden.common.mybatis.core.page.PageQuery;
import cn.cdeden.system.api.domain.vo.RemoteUserFeedBackVO;
import cn.cdeden.system.api.model.DeptDTO;
import cn.cdeden.system.domain.SysUserRole;
import cn.cdeden.system.domain.vo.*;
import cn.cdeden.system.mapper.SysUserRoleMapper;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.PageUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.dubbo.config.annotation.DubboService;
import cn.cdeden.common.core.enums.UserStatus;
import cn.cdeden.common.core.exception.ServiceException;
import cn.cdeden.common.core.exception.user.UserException;
import cn.cdeden.common.core.utils.DateUtils;
import cn.cdeden.common.core.utils.MapstructUtils;
import cn.cdeden.common.core.utils.StringUtils;
import cn.cdeden.common.mybatis.helper.DataPermissionHelper;
import cn.cdeden.common.tenant.helper.TenantHelper;
import cn.cdeden.system.api.RemoteUserService;
import cn.cdeden.system.api.domain.bo.RemoteUserBo;
import cn.cdeden.system.api.domain.vo.RemoteUserVo;
import cn.cdeden.system.api.model.LoginUser;
import cn.cdeden.system.api.model.RoleDTO;
import cn.cdeden.system.api.model.XcxLoginUser;
import cn.cdeden.system.domain.SysUser;
import cn.cdeden.system.domain.bo.SysUserBo;
import cn.cdeden.system.mapper.SysUserMapper;
import cn.cdeden.system.service.*;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 用户服务
 *
 * @author Lion Li
 */
@RequiredArgsConstructor
@Service
@DubboService
public class RemoteUserServiceImpl implements RemoteUserService {

    private final ISysUserService userService;
    private final ISysPermissionService permissionService;
    private final ISysConfigService configService;
    private final ISysRoleService roleService;
    private final ISysDeptService deptService;
    private final SysUserMapper userMapper;
    private final SysUserRoleMapper userRoleMapper;
    private final ISysPostService postService; // 岗位


    /**
     * 通过用户名查询用户信息
     *
     * @param username 用户名
     * @param tenantId 租户id
     * @return 结果
     */
    @Override
    public LoginUser getUserInfo(String username, String tenantId) throws UserException {
        return TenantHelper.dynamic(tenantId, () -> {
            SysUserVo sysUser = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, username));
            if (ObjectUtil.isNull(sysUser)) {
                throw new UserException("user.not.exists", username);
            }
            if (UserStatus.DISABLE.getCode().equals(sysUser.getStatus())) {
                throw new UserException("user.blocked", username);
            }
            // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
            // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
            return buildLoginUser(sysUser);
        });
    }

    public LoginUser getUserInfo(String username, String tenantId, String loginType) throws UserException {
        return TenantHelper.dynamic(tenantId, () -> {
            SysUserVo sysUser = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, username));
            if (ObjectUtil.isNull(sysUser)) {
                throw new UserException("user.not.exists", username);
            }
            if (UserStatus.DISABLE.getCode().equals(sysUser.getStatus())) {
                throw new UserException("user.blocked", username);
            }
            // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
            // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
            return buildLoginUser(sysUser, loginType);
        });
    }

    /**
     * 通过用户名查询用户信息
     *
     * @param userId 用户id
     * @return 结果
     */
    @Override
    public LoginUser getUserInfo(Long userId) throws UserException {

        SysUserVo sysUser = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserId, userId));
        if (ObjectUtil.isNull(sysUser)) {
            throw new UserException("user.not.exists", userId);
        }
        if (UserStatus.DISABLE.getCode().equals(sysUser.getStatus())) {
            throw new UserException("user.blocked", userId);
        }
        // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
        // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
        return buildLoginUser(sysUser);

    }

    /**
     * 通过用户id查询用户信息
     *
     * @param userId   用户id
     * @param tenantId 租户id
     * @return 结果
     */
    @Override
    public LoginUser getUserInfo(Long userId, String tenantId) throws UserException {
        return TenantHelper.dynamic(tenantId, () -> {
            SysUserVo sysUser = userMapper.selectVoById(userId);
            if (ObjectUtil.isNull(sysUser)) {
                throw new UserException("user.not.exists", "");
            }
            if (UserStatus.DISABLE.getCode().equals(sysUser.getStatus())) {
                throw new UserException("user.blocked", sysUser.getUserName());
            }
            // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
            // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
            return buildLoginUser(sysUser);
        });
    }

    /**
     * 通过手机号查询用户信息
     *
     * @param phonenumber 手机号
     * @param tenantId    租户id
     * @return 结果
     */
    @Override
    public LoginUser getUserInfoByPhonenumber(String phonenumber, String tenantId) throws UserException {
        return TenantHelper.dynamic(tenantId, () -> {
            SysUserVo sysUser = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getPhonenumber, phonenumber));
            if (ObjectUtil.isNull(sysUser)) {
                throw new UserException("user.not.exists", phonenumber);
            }
            if (UserStatus.DISABLE.getCode().equals(sysUser.getStatus())) {
                throw new UserException("user.blocked", phonenumber);
            }
            // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
            // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
            return buildLoginUser(sysUser);
        });
    }

    /**
     * 通过邮箱查询用户信息
     *
     * @param email    邮箱
     * @param tenantId 租户id
     * @return 结果
     */
    @Override
    public LoginUser getUserInfoByEmail(String email, String tenantId) throws UserException {
        return TenantHelper.dynamic(tenantId, () -> {
            SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getEmail, email));
            if (ObjectUtil.isNull(user)) {
                throw new UserException("user.not.exists", email);
            }
            if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
                throw new UserException("user.blocked", email);
            }
            // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
            // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
            return buildLoginUser(user);
        });
    }

    /**
     * 通过openid查询用户信息
     *
     * @param openid openid
     * @return 结果
     */
    @Override
    public XcxLoginUser getUserInfoByOpenid(String openid) throws UserException {
        // todo 自行实现 userService.selectUserByOpenid(openid);
        SysUser sysUser = new SysUser();
        if (ObjectUtil.isNull(sysUser)) {
            // todo 用户不存在 业务逻辑自行实现
        }
        if (UserStatus.DISABLE.getCode().equals(sysUser.getStatus())) {
            // todo 用户已被停用 业务逻辑自行实现
        }
        // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
        // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
        XcxLoginUser loginUser = new XcxLoginUser();
        loginUser.setUserId(sysUser.getUserId());
        loginUser.setUsername(sysUser.getUserName());
        loginUser.setNickname(sysUser.getNickName());
        loginUser.setUserType(sysUser.getUserType());
        loginUser.setOpenid(openid);
        return loginUser;
    }

    /**
     * 注册用户信息
     *
     * @param remoteUserBo 用户信息
     * @return 结果
     */
    @Override
    public Boolean registerUserInfo(RemoteUserBo remoteUserBo) throws UserException, ServiceException {
        SysUserBo sysUserBo = MapstructUtils.convert(remoteUserBo, SysUserBo.class);
        String username = sysUserBo.getUserName();
        boolean exist = TenantHelper.dynamic(remoteUserBo.getTenantId(), () -> {
            if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) {
                throw new ServiceException("当前系统没有开启注册功能");
            }
            return userMapper.exists(new LambdaQueryWrapper<SysUser>()
                .eq(SysUser::getUserName, sysUserBo.getUserName()));
        });
        if (exist) {
            throw new UserException("user.register.save.error", username);
        }
        return userService.registerUser(sysUserBo, remoteUserBo.getTenantId());
    }

    /**
     * 通过用户ID查询用户账户
     *
     * @param userId 用户ID
     * @return 用户账户
     */
    @Override
    public String selectUserNameById(Long userId) {
        return userService.selectUserNameById(userId);
    }

    /**
     * 通过用户ID查询用户昵称
     *
     * @param userId 用户ID
     * @return 用户昵称
     */
    @Override
    public String selectNicknameById(Long userId) {
        return userService.selectNicknameById(userId);
    }

    /**
     * 通过用户ID查询用户账户
     *
     * @param userIds 用户ID 多个用逗号隔开
     * @return 用户账户
     */
    @Override
    public String selectNicknameByIds(String userIds) {
        return userService.selectNicknameByIds(userIds);
    }

    /**
     * 通过用户ID查询用户手机号
     *
     * @param userId 用户id
     * @return 用户手机号
     */
    @Override
    public String selectPhonenumberById(Long userId) {
        return userService.selectPhonenumberById(userId);
    }

    /**
     * 通过用户ID查询用户邮箱
     *
     * @param userId 用户id
     * @return 用户邮箱
     */
    @Override
    public String selectEmailById(Long userId) {
        return userService.selectEmailById(userId);
    }

    /**
     * 构建登录用户
     */
    private LoginUser buildLoginUser(SysUserVo userVo, String loginType) {
        LoginUser loginUser = new LoginUser();
        loginUser.setTenantId(userVo.getTenantId());
        loginUser.setUserId(userVo.getUserId());
        loginUser.setDeptId(userVo.getDeptId());
        loginUser.setUsername(userVo.getUserName());
        loginUser.setNickname(userVo.getNickName());
        loginUser.setPassword(userVo.getPassword());
        loginUser.setUserType(userVo.getUserType());
        if (UserType.FRONT_USER.getUserType().equals(loginType))
            loginUser.setUserType(UserType.FRONT_USER.getUserType());
        loginUser.setMenuPermission(permissionService.getMenuPermission(userVo.getUserId()));
        loginUser.setFrontMenuPermission(permissionService.getFrontMenuPermission(userVo.getUserId()));
        loginUser.setRolePermission(permissionService.getRolePermission(userVo.getUserId()));
        if (ObjectUtil.isNotNull(userVo.getDeptId())) {
            Opt<SysDeptVo> deptOpt = Opt.of(userVo.getDeptId()).map(deptService::selectDeptById);
            loginUser.setDeptName(deptOpt.map(SysDeptVo::getDeptName).orElse(StringUtils.EMPTY));
            loginUser.setDeptCategory(deptOpt.map(SysDeptVo::getDeptCategory).orElse(StringUtils.EMPTY));
        }
        List<SysRoleVo> roles = roleService.selectRolesByUserId(userVo.getUserId());
        loginUser.setRoles(BeanUtil.copyToList(roles, RoleDTO.class));
        return loginUser;
    }

    /**
     * 构建登录用户
     */
    private LoginUser buildLoginUser(SysUserVo userVo) {
        LoginUser loginUser = new LoginUser();
        loginUser.setTenantId(userVo.getTenantId());
        loginUser.setUserId(userVo.getUserId());
        loginUser.setDeptId(userVo.getDeptId());
        loginUser.setUsername(userVo.getUserName());
        loginUser.setNickname(userVo.getNickName());
        loginUser.setPassword(userVo.getPassword());
        loginUser.setUserType(userVo.getUserType());
        loginUser.setMinioBucket(userVo.getMinioBucket());
        loginUser.setMenuPermission(permissionService.getMenuPermission(userVo.getUserId()));
        loginUser.setFrontMenuPermission(permissionService.getFrontMenuPermission(userVo.getUserId()));
        loginUser.setRolePermission(permissionService.getRolePermission(userVo.getUserId()));
        if (ObjectUtil.isNotNull(userVo.getDeptId())) {
            Opt<SysDeptVo> deptOpt = Opt.of(userVo.getDeptId()).map(deptService::selectDeptById);
            loginUser.setDeptName(deptOpt.map(SysDeptVo::getDeptName).orElse(StringUtils.EMPTY));
            loginUser.setDeptCategory(deptOpt.map(SysDeptVo::getDeptCategory).orElse(StringUtils.EMPTY));
        }
        // 获取用户部门上级信息
        List<SysDeptVo> superiorAll = deptService.getSuperiorAll(userVo.getDeptId());
        loginUser.setDeptIds(BeanUtil.copyToList(superiorAll, DeptDTO.class));

        // 获取用户岗位信息
        List<Long> postList = postService.selectPostListByUserId(userVo.getUserId());
        loginUser.setPostIds(postList);

        // 获取用户角色信息
        List<SysRoleVo> roles = roleService.selectRolesByUserId(userVo.getUserId());
        loginUser.setRoles(BeanUtil.copyToList(roles, RoleDTO.class));
        return loginUser;
    }

    /**
     * 更新用户信息
     *
     * @param userId 用户ID
     * @param ip     IP地址
     */
    @Override
    public void recordLoginInfo(Long userId, String ip) {
        SysUser sysUser = new SysUser();
        sysUser.setUserId(userId);
        sysUser.setLoginIp(ip);
        sysUser.setLoginDate(DateUtils.getNowDate());
        sysUser.setUpdateBy(userId);
        DataPermissionHelper.ignore(() -> userMapper.updateById(sysUser));
    }

    /**
     * 通过用户ID查询用户列表
     *
     * @param userIds 用户ids
     * @return 用户列表
     */
    @Override
    public List<RemoteUserVo> selectListByIds(List<Long> userIds) {
        List<SysUserVo> sysUserVos = userService.selectUserByIds(userIds, null);
        return MapstructUtils.convert(sysUserVos, RemoteUserVo.class);
    }

    @Override
    public List<RemoteUserVo> selectListAll() {
        return MapstructUtils.convert(userMapper.selectList(), RemoteUserVo.class);
    }

    @Override
    public List<RemoteUserVo> select(String nickName, Set<Long> deptId) {
        List<SysUser> sysUsers = userMapper.selectList(new LambdaQueryWrapper<SysUser>().like(SysUser::getUserName, nickName).in(SysUser::getDeptId, deptId));
        return MapstructUtils.convert(sysUsers, RemoteUserVo.class);
    }

    /**
     * 通过角色ID查询用户ID
     *
     * @param roleIds 角色ids
     * @return 用户ids
     */
    @Override
    public List<Long> selectUserIdsByRoleIds(List<Long> roleIds) {
        return userService.selectUserIdsByRoleIds(roleIds);
    }

    @Override
    public RemoteUserVo selectUserByUserName(String userName) {
//        return baseMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, userName));
//        SysUserVo sysUserVo = userService.selectUserByUserName(userName);
//        return userService.selectUserByUserName(userName);
        return MapstructUtils.convert(userService.selectUserByUserName(userName), RemoteUserVo.class);
    }

    @Override
    public RemoteUserVo selectUserByUserId(Long userId) {
        return MapstructUtils.convert(userService.selectUserByUserId(userId), RemoteUserVo.class);
    }

    @Override
    public List<RemoteUserVo> selectUserAllByUserId(List<Long> userIds) {
        return MapstructUtils.convert(userService.selectUserAllByUserId(userIds), RemoteUserVo.class);
    }

    @Override
    public Integer updateMinioBucket(String bucketName, Long userId) {
        return userService.updateMinioBucket(bucketName, userId);
    }

    @Override
    public boolean upperLimit(String userId, long size) {
        if (userId == null) {
            return true;
        }

        SysUserVo byId = userService.selectUserById(Long.valueOf(userId));
//        User byId = this.getById(userId);
        if (ObjectUtils.isEmpty(byId)) {
            throw new RuntimeException("非法的用户编号");
        }

        Long use = byId.getStorageUse();
        long storageUse = use != null ? use : 0l;


        Long sum = byId.getStorageSum();
        long storageSum = sum != null ? sum : 0l;
        return storageUse + size > storageSum;
    }

    @Override
    public boolean updateBatchById(List<RemoteUserVo> userList) {
        return userService.updateBatchById(userList);
    }

    @Override
    public boolean updateStorageSum(String userId, long size) {
        if (size > 0) {
            int i = userMapper.updateStorageSum(userId, size);
//            int i = sysUserMapper.updateStorageSum(userId, size);
            return i > 0;
        }
        return true;
    }

    @Override
    public boolean updateStorageLess(String userId, long size) {
        if (size > 0) {
            int i = userMapper.updateStorageLess(userId, size);
//            int i = sysUserMapper.updateStorageLess(userId, size);
            return i > 0;
        }
        return true;
    }

    @Override
    public boolean updateStorageUpDate(String userId, long originalSize, long newSize) {
        if (newSize > 0) {
            int i = userMapper.updateStorageUpDate(userId, originalSize, newSize);
//            int i = sysUserMapper.updateStorageUpDate(userId, originalSize,newSize);
            return i > 0;
        }


        return true;
    }

    @Override
    public int save(RemoteUserVo newUser, Object o) {
        return userService.insertUser(MapstructUtils.convert(newUser, SysUserBo.class));
    }

    @Override
    public int saveUserRole(Long userId, long roleId) {
        SysUserRole sysUserRole = new SysUserRole();
        sysUserRole.setUserId(userId);
        sysUserRole.setRoleId(roleId);
        return userRoleMapper.insert(sysUserRole);
    }


    @Override
    public int updateById(RemoteUserVo existingUser) {
        return userService.updateUser(MapstructUtils.convert(existingUser, SysUserBo.class));
    }

    @Override
    public boolean checkPerm(Long userId, String permission) {
        if (userId == 1) {
            return true;
        }
        List<SysUserPermVo> sysUserPermVos = userService.checkPerm(userId);
        List<String> sysUserRoles = sysUserPermVos.stream().map(SysUserPermVo::getDataScope).collect(Collectors.toList());
        if (sysUserRoles.contains("1")) {
            return true;
        }
        List<String> perms = sysUserPermVos.stream().map(SysUserPermVo::getPerms).collect(Collectors.toList());
        if (perms.contains("fileManage:recycle:list")) {
            return true;
        }
        return false;
    }

    @Override
    public TableDataInfo<RemoteUserVo> getUserPage(List<Long> userIdList,int pageSize,int pageNum) {
        // 创建分页对象
        Page<SysUserVo> page = new Page<>(pageNum, pageSize);

        // 调用Mapper方法进行分页查询
        IPage<SysUserVo> userPage = userMapper.getUserPage(page, userIdList);
        return MapstructUtils.convertTableDataInfo(TableDataInfo.build(userPage),RemoteUserVo.class);
    }

    @Override
    public List<RemoteUserFeedBackVO> getUserAndFeedBack(Long id, List<Integer> userIdList) {
        return MapstructUtils.convert(userMapper.getUserAndFeedBack(id, userIdList),RemoteUserFeedBackVO.class);
    }

    @Override
    public List<LoginUser> selectUserByNickName(String nickName) {
        List<SysUserVo> sysUser = userService.selectUserByNickName(nickName);
        List<LoginUser> loginUsers = new ArrayList<>();
        sysUser.forEach(sysUserVo -> loginUsers.add(buildLoginUser(sysUserVo)));
        return loginUsers;
    }

    @Override
    public List<Long> likeUserNames(String userName) {
        List<SysUserVo> sysUserVos = userMapper.selectUserList(new LambdaQueryWrapper<SysUser>()
            .like(SysUser::getNickName, "%" + userName + "%"));
        return sysUserVos.stream().map(SysUserVo::getUserId).collect(Collectors.toList());
    }
}
